package webmarket.common;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.apache.logging.log4j.Level;

import webmarket.common.MarkerController.MarkerTypes;
import webmarket.controller.ControllerBase;
import webmarket.model.Shopcategory;

public final class ShopcategoryController extends ControllerBase {
	private ShopcategoryController() {
	}

	private static int idCounter = 0;

	private static final String persistentResource = "shopcategories.xml";

	private static final Map<Integer, Shopcategory> idCache = new HashMap<Integer, Shopcategory>();
	private static final Map<String, Shopcategory> nameCache = new HashMap<String, Shopcategory>();

	private static Shopcategory root;
	static {
		read();
	}

	public static void read() {
		logger.entry();
		try {
			JAXBContext jc = JAXBContext.newInstance(Shopcategory.class);
			Unmarshaller u = jc.createUnmarshaller();
			InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(persistentResource);
			if (inputStream != null) {
				setRoot((Shopcategory) u.unmarshal(new InputStreamReader(inputStream)));
			} else {
				logger.warn(MarkerController.getMarker(MarkerTypes.INTERNAL_ERROR), "Nem sikerült beolvasni a piac kategóriák leíróját");
			}
		} catch (JAXBException e) {
			logger.catching(Level.DEBUG, e);
		}
		logger.exit("baseCategoryCount:" + getRoot().getChildren().size());
	}

	public static void refreshCache() {
		logger.entry();
		idCache.clear();
		nameCache.clear();
		addAllChildren(getRoot());
		logger.exit("totalCategoryCount:" + idCache.size());
	}

	public static List<String> getForSelect() {
		List<String> list = new ArrayList<String>();
		for (Shopcategory child : root.getChildren()) {
			putAllChildrenAsHtmlOption(child, list);
			list.add("<option data-divider=\"true\"></option>");
		}
		return list;
	}

	private static void putAllChildrenAsHtmlOption(Shopcategory category, List<String> list) {
		list.add(toHtmlOption(category));
		for (Shopcategory child : category.getChildren()) {
			putAllChildrenAsHtmlOption(child, list);
		}
	}

	public static List<String> getLeafsForSelect() {
		List<String> list = new ArrayList<String>();
		for (Shopcategory child : root.getChildren()) {
			putAllLeafsAsHtmlOption(child, list);
		}
		return list;
	}

	private static String toHtmlOption(Shopcategory category) {
		String label = CommonMethods.printCategory(category);
		String icon = CommonMethods.getIcon(category);
		String dataIcon = icon != null ? " data-icon=\"icon-" + icon + "\"" : "";
		return "<option value=\"" + category.getId() + "\"" + dataIcon + ">" + label + "</option>";
	}

	private static void putAllLeafsAsHtmlOption(Shopcategory category, List<String> list) {
		if (category.getChildren().size() == 0) {
			list.add(toHtmlOption(category));
		} else {
			for (Shopcategory child : category.getChildren()) {
				putAllLeafsAsHtmlOption(child, list);
			}
		}
	}

	private static void addAllChildren(Shopcategory category) {
		for (Shopcategory child : category.getChildren()) {
			idCache.put(child.getId(), child);
			nameCache.put(child.getName(), child);
			addAllChildren(child);
			child.setParent(category);
		}
	}

	public static Shopcategory get(String name) {
		return nameCache.get(name);
	}

	public static Shopcategory get(int id) {
		return idCache.get(id);
	}

	public static void persist() throws JAXBException, FileNotFoundException {
		logger.entry();
		try {
			JAXBContext jc = JAXBContext.newInstance(Shopcategory.class);
			// A sorosított típusok csomagneve
			Marshaller m = jc.createMarshaller();
			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			// Hogy szépen legyen formázva
			URL resource = Thread.currentThread().getContextClassLoader().getResource(persistentResource);
			m.marshal(getRoot(), new FileOutputStream(resource.getPath(), false));
			logger.exit(resource.getPath());
		} catch (JAXBException | FileNotFoundException e) {
			logger.catching(Level.DEBUG,e);
			throw e;
		}
	}

	public static Shopcategory create(String name, String description, Shopcategory... children) {
		return create(name, description, "", children);
	}

	public static Shopcategory create(String name, String description, String[]... children) {
		return create(name, description, "", children);
	}

	public static Shopcategory create(String name, String description, String icon, Shopcategory... children) {
		Shopcategory shopcategory = create(name, description, icon);
		for (Shopcategory child : children) {
			shopcategory.getChildren().add(child);
			child.setParent(shopcategory);
		}
		return shopcategory;
	}

	public static Shopcategory create(String name, String description, String icon, String[]... children) {
		Shopcategory[] childrenCategories = new Shopcategory[children.length];
		for (int i = 0; i < children.length; i++) {
			if (children[i].length == 3) {
				childrenCategories[i] = create(children[i][0], children[i][1], children[i][2]);
			} else {
				childrenCategories[i] = create(children[i][0], children[i][1]);
			}
		}
		return create(name, description, icon, childrenCategories);
	}

	public static Shopcategory create(String name, String description) {
		return create(name, description, "");
	}

	public static Shopcategory create(String name, String description, String icon) {
		Shopcategory shopcategory = new Shopcategory();
		shopcategory.setName(name);
		shopcategory.setDescription(description);
		shopcategory.setIcon(icon);
		synchronized (persistentResource) {
			shopcategory.setId(idCounter++);
		}
		return shopcategory;
	}

	public static List<Shopcategory> getAllChildren(int id) {
		Shopcategory parent = get(id);
		List<Shopcategory> allChildren = getAllChildren(parent);
		return allChildren;
	}

	public static List<Shopcategory> getAllChildren(String name) {
		return getAllChildren(get(name));
	}

	public static List<Shopcategory> getAllChildren(Shopcategory category) {
		return addAllChildren(category, new ArrayList<Shopcategory>());
	}

	public static List<Shopcategory> addAllChildren(int id, List<Shopcategory> list) {
		return addAllChildren(get(id), list);
	}

	public static List<Shopcategory> addAllChildren(String name, List<Shopcategory> list) {
		return addAllChildren(get(name), list);
	}

	public static List<Shopcategory> addAllChildren(Shopcategory category, List<Shopcategory> list) {
		for (Shopcategory child : category.getChildren()) {
			list.add(child);
			addAllChildren(child, list);
		}
		return list;
	}

	/**
	 * @return the root
	 */
	public static Shopcategory getRoot() {
		return root;
	}

	/**
	 * @param root
	 *            the root to set
	 */
	public static void setRoot(Shopcategory root) {
		ShopcategoryController.root = root;
		if (root != null) {
			refreshCache();
		}
	}

}
